/**
 * 图片压缩工具
 * 用于将图片压缩到指定大小，支持PNG和JPG格式
 */

/**
 * 图片压缩配置
 */
export interface CompressOptions {
  /** 最大文件大小（KB） */
  maxSizeKB?: number;
  /** 最大边长（像素） */
  maxDimension?: number;
  /** 最低质量（0-1） */
  minQuality?: number;
  /** 输出格式 */
  outputFormat?: 'jpeg' | 'png';
}

/**
 * 压缩结果
 */
export interface CompressResult {
  /** 压缩后的数据URL */
  dataURL: string;
  /** 文件对象 */
  file: File;
  /** 压缩后文件大小（字节） */
  size: number;
  /** 压缩后宽度 */
  width: number;
  /** 压缩后高度 */
  height: number;
  /** 实际使用的质量系数 */
  quality: number;
}

/**
 * 压缩图片到指定大小
 * @param file 原始文件
 * @param options 压缩配置
 * @returns Promise<CompressResult>
 */
export const compressImage = (
  file: File,
  options: CompressOptions = {}
): Promise<CompressResult> => {
  return new Promise((resolve, reject) => {
    const {
      maxSizeKB = 10,
      maxDimension = 200,
      minQuality = 0.1,
      outputFormat = 'jpeg'
    } = options;

    // 验证文件类型
    if (!/^image\/(png|jpeg)$/.test(file.type)) {
      reject(new Error('仅支持PNG和JPG格式图片'));
      return;
    }

    const img = new Image();
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    if (!ctx) {
      reject(new Error('浏览器不支持Canvas'));
      return;
    }

    img.onload = () => {
      try {
        // 计算目标尺寸
        let { width, height } = img;

        // 保持宽高比，限制最大边长
        if (width > height && width > maxDimension) {
          height = Math.round((height * maxDimension) / width);
          width = maxDimension;
        } else if (height > maxDimension) {
          width = Math.round((width * maxDimension) / height);
          height = maxDimension;
        }

        canvas.width = width;
        canvas.height = height;

        // 清除画布
        ctx.clearRect(0, 0, width, height);

        // 绘制图片
        ctx.drawImage(img, 0, 0, width, height);

        // 递归压缩直到满足大小要求
        let quality = 0.8;
        const targetType = `image/${outputFormat}`;

        const compress = () => {
          const dataURL = canvas.toDataURL(targetType, quality);

          // 估算文件大小 (base64编码后的大小)
          const sizeKB = (dataURL.length * 3) / 4 / 1024;

          if (sizeKB <= maxSizeKB || quality <= minQuality) {
            // 转换为File对象
            const compressedFile = dataURLtoFile(
              dataURL,
              `compressed_${Date.now()}.${outputFormat}`
            );

            resolve({
              dataURL,
              file: compressedFile,
              size: compressedFile.size,
              width,
              height,
              quality: Math.round(quality * 100) / 100
            });
          } else {
            quality -= 0.1;
            compress();
          }
        };

        compress();
      } catch (error) {
        reject(error);
      }
    };

    img.onerror = () => {
      reject(new Error('图片加载失败'));
    };

    img.src = URL.createObjectURL(file);
  });
};

/**
 * 从数据URL创建文件对象
 * @param dataURL 数据URL
 * @param filename 文件名
 * @returns File对象
 */
export const dataURLtoFile = (dataURL: string, filename: string): File => {
  const arr = dataURL.split(',');
  if (arr.length < 2 || !arr[0] || !arr[1]) {
    throw new Error('Invalid data URL');
  }
  const mimeMatch = arr[0].match(/:(.*?);/);
  const mime = mimeMatch?.[1] ?? 'image/jpeg';
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
};

/**
 * 验证图片文件
 * @param file 要验证的文件
 * @returns boolean
 */
export const validateImageFile = (file: File): { valid: boolean; message?: string } => {
  // 检查文件类型
  if (!/^image\/(png|jpeg)$/.test(file.type)) {
    return {
      valid: false,
      message: '仅支持PNG和JPG格式图片'
    };
  }

  // 检查文件大小（前端预检，5MB以内）
  const maxSize = 10 * 1024 * 1024; // 5MB
  if (file.size > maxSize) {
    return {
      valid: false,
      message: '图片大小不能超过10MB'
    };
  }

  return { valid: true };
};
